//日志格式化模块
//作用:对日志消息进行格式化,组织成为指定格式的字符串
//格式化字符串控制了日志的输出格式
//定义格式化字符串,是为了让日志系统进行日志格式化更加的灵活方便
//成员:
//1.格式化字符串
//2.格式化子项数组:对格式化字符串进行解析,保存了日志消息要素的排序
//不同的格式化子项,会从日志消息中去除指定的消息元素,转换为字符串
//需要先完成的:格式化子项类的实现和定义
//作用:从日志消息中取出指定的元素,追加到内存空间中
//设计思想:
//1.抽象一个格式化子项的基类
//2.基于基类,派生出不同的格式化子类子项
// 时间   线程ID 日志等级 文件目录 文件名 行号  消息主体 换行符 制表符  日志器名称 其他
//这样就可以在父类中定义父类指针的数组,指向不同的格式化子项子类的对象


#ifndef __M_FMT_H__
#define __M_FMT_H__
#include<ctime>
#include<vector>
#include<cassert>
#include<sstream>
#include"util.hpp"
#include"level.hpp"
#include"message.hpp"

namespace zllog
{
    //抽像格式化子项基类
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void format(std::ostream& out,const LogMsg& msg) = 0; 
    };
    //派生类格式化子项子类---消息,等级,时间,文件名,线程ID,日志器名,制表符,换行,其他
    class MsgFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<msg._payload;
        }
    };
    class LevelFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<LogLevel::ToString(msg._level);
        }
    };
    class TimeFormatItem : public FormatItem   
    {
    public:
        TimeFormatItem(const std::string& fmt = "%H:%M:%S") //将时间戳格式定义为"%H:%M:%S"
            :_time_fmt(fmt)
        {}
        
        void format(std::ostream& out,const LogMsg& msg) override
        {
            struct tm t;
            localtime_r(&msg._ctime,&t);                     
            char tmp[32] = {0};
            strftime(tmp,sizeof(tmp),_time_fmt.c_str(),&t);
            out<<tmp;
        }
    private:
        std::string _time_fmt;      //定义一个时间戳输入格式
    };
    class FileFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<msg._file;
        }
    };
    class LineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<msg._line;
        }
    };
    class ThreadFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<msg._tid;
        }
    };
    class LoggerFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<msg._logger;
        }
    };
    class TabFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<"\t";
        }
    };
    class NLFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<"\n";
        }
    };
    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const std::string& str)
            :_str(str)
        {}
        void format(std::ostream& out,const LogMsg& msg) override
        {
            out<<_str;
        }
    private:
        std::string _str;
    };

    //%d 表示日期,包含子格式{%%H:%M:%S}
    //%t 表示线程ID
    //%c 表示日志器名称
    //%f 表示源代码文件名
    //%l 表示源码行号
    //%p 表示日志等级
    //%T 表示制表符缩进
    //%m 表示消息主体
    //%n 表示换行符
    class FormatMatter
    {
    public:
        using ptr = std::shared_ptr<FormatMatter>;
        FormatMatter(const std::string& pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
            :_pattern(pattern)
        {
            assert(parsePattern());
        }
        //对msg进行格式化
        void format(std::ostream& out,const LogMsg& msg)
        {
            for(auto& item: _items)
            {
                item->format(out,msg);
            }
        }
        std::string format(const LogMsg& msg)
        {
            std::stringstream ss;
            format(ss,msg);
            return ss.str();
        }
        //对格式化字符串进行解析
        //在处理过程中,需要将处理得到的信息保存下来
        //例如:abcdef[%d{%H:%M:%S}][%p]%T%m%n
        //处理思想:
        //没有以%起始的字符串都是原始字符串
        //不是%,则往后走,直到遇到%,则是起始字符串的结束
        //遇到%,看看紧随其后的字符是不是也是%,如果是就代表他是%字符
        //如果不是,就代表紧随其后的这个字符是格式化字符
        //紧随格式化字符之后,有没有{ ,如果有,则{之后, }之前的数据都是格式化字符



        //key = nullptr , val = abcdef[
        //key = d ,val = %H:%M:%S
        //key = nullptr ,val = ][
        //key = p , val = nullptr
        //key = nullptr , val = ]
        //key = T ,val = null
        //key = m , val = null
        //key = n , val = null

        //得到了数组后,根据数组内容,创建对应的格式化子项对象,添加到items成员数组中
    private:
        bool parsePattern()
        {
            //例子
            //[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n
            //abcd[%%%d{%H:%M:%S}][%p]%T%m%
            //abc%%abc[%d{%H:%M:%S] %m%n
            //abc%%a%gbc[%d{%H:%M:%S}] %m%g%n
            std::vector<std::pair<std::string,std::string>> fmt_order;
            size_t pos = 0;
            std::string key,val;
            //1.统一处理原始字符串--判断是否是%--不是就是原始字符串
            while(pos < _pattern.size())
            {
                if(_pattern[pos] != '%')
                {
                    val.push_back(_pattern[pos++]);
                }
                else
                {
                    //能走下来就代表pos位置就是%字符,%%处理成为一个原始字符%
                    if(pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                    {
                        val.push_back('%');
                        pos += 2;
                    }
                    //代表%后面是个格式化字符,也代表原始字符串处理完毕
                    else if(pos + 1 == _pattern.size()) return false;
                    else if(pos + 1 < _pattern.size() && _pattern[pos + 1] != '%')
                    {
                        fmt_order.push_back(make_pair("",val));
                        val.clear();
                        
                        
                        pos += 1;
                        key = _pattern[pos];
                        pos += 1;
                        if(pos + 1 < _pattern.size() && _pattern[pos] == '{')
                        {
                            pos += 1;
                            while(pos < _pattern.size() && _pattern[pos] != '}')
                            {
                                val.push_back(_pattern[pos++]);
                            }
                            if(pos == _pattern.size())
                            {
                                std::cout<<"子规则出错"<<std::endl;
                                return false;
                            }
                            pos += 1;

                        }
                        fmt_order.push_back(make_pair(key,val));
                        val.clear();
                        key.clear();
                    }
                }
            }
            //2.根据解析得到的数据初始化格式化子项数组成员
            for(auto& it : fmt_order)
            {
                _items.push_back(createItem(it.first,it.second));
            }
            return true;
        }
    
        //根据不同的格式化字符串创建不同的格式化子项对象
        FormatItem::ptr createItem(const std::string& key,const std::string& val)
        {
            if(key == "d") return std::make_shared<TimeFormatItem>(val);
            if(key == "t") return std::make_shared<ThreadFormatItem>();
            if(key == "c") return std::make_shared<LoggerFormatItem>();
            if(key == "f") return std::make_shared<FileFormatItem>();
            if(key == "l") return std::make_shared<LineFormatItem>();
            if(key == "p") return std::make_shared<LevelFormatItem>();
            if(key == "T") return std::make_shared<TabFormatItem>();
            if(key == "m") return std::make_shared<MsgFormatItem>();
            if(key == "n") return std::make_shared<NLFormatItem>();
            if(key == "") return std::make_shared<OtherFormatItem> (val);
            std::cout<<"没有对应的格式化字符"<<key<<std::endl;
            abort();
            return FormatItem::ptr();
        }
    private:
        std::string _pattern;  //格式化规则字符串
        std::vector<FormatItem::ptr> _items;
        
    };

};




#endif